<?php

namespace app\common\repositories\activity\lottery;


use app\common\dao\activity\lottery\LuckLotteryDao;
use app\common\dao\activity\lottery\LuckPrizeDao;
use app\common\model\activity\lottery\LuckPrize;
use app\common\repositories\BaseRepository;
use app\common\repositories\store\coupon\StoreCouponRepository;
use app\common\repositories\store\product\ProductRepository;
use app\common\repositories\user\UserIntegralBillRepository;
use app\common\repositories\user\UserRepository;
use app\controller\api\activity\LuckLottery;
use crmeb\services\CacheServices;
use think\exception\ValidateException;
use think\facade\Db;

class LuckLotteryRepository extends BaseRepository
{
    public function __construct(LuckLotteryDao $dao)
    {
        $this->dao = $dao;
    }

    /**
     * 抽奖形式，奖品数量
     * @var int[]
     */
    protected  $lottery_type = [
        '1' => 8 //九宫格
    ];
    /**
     * 抽奖类型
     * @var string[]
     */
    protected  $lottery_factor = [
        '1' => '积分',
        '2' => '余额',
        '3' => '下单支付成功',
        '4' => '订单评价',
        '5' => '关注公众号'
    ];

    public function getList(array $where,$page,$limit)
    {
        $query = $this->dao->search($where)->with('prize');
        $count = $query->count();
        $list = $query->page($page,$limit)->select();
        $luckLotteryRecordRepository = app()->make(LuckLotteryRecordRepository::class);
        foreach ($list as &$item) {
            $item['lottery_type'] = $lottery_factor[$item['factor']] ?? '';
            $data = $luckLotteryRecordRepository->getLotteryRecordData((int)$item['id']);
            $item['lottery_all'] = $data['all'] ?? 0;
            $item['lottery_people'] = $data['people'] ?? 0;
            $item['lottery_win'] = $data['win'] ?? 0;
            if ($item['status']) {
                if ($item['start_time'] == 0 && $item['end_time'] == 0) {
                    $item['lottery_status'] = '进行中';
                } else {
                    if ($item['start_time'] > time())
                        $item['lottery_status'] = '未开始';
                    else if ($item['end_time'] < time())
                        $item['lottery_status'] = '已结束';
                    else if ($item['end_time'] > time() && $item['start_time'] < time()) {
                        $item['lottery_status'] = '进行中';
                    }
                }
            } else $item['lottery_status'] = '已结束';
            $item['start_time'] = $item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '';
            $item['end_time'] = $item['end_time'] ? date('Y-m-d H:i:s', $item['end_time']) : '';
        }
        return compact('count','list');

    }


    public function getlotteryFactorInfo(int $factor)
    {
        $lottery = $this->dao->getFactorLottery($factor, '*', ['prize'], false);
        if (!$lottery) {
            return [];
        }
        $lottery = $lottery->toArray();
        if (isset($lottery['prize']) && $lottery['prize']) {
            $products = $coupons = [];
            $product_ids = array_unique(array_column($lottery['prize'], 'product_id'));
            $coupon_ids = array_unique(array_column($lottery['prize'], 'coupon_id'));
            $productServices = app()->make(ProductRepository::class);
            $products = $productServices->selectWhere([['product_id', 'in', $product_ids]],'product_id,store_name,image')->toArray();
            $products = array_column($products,null,'product_id');
            $couponServices = app()->make(StoreCouponRepository::class);
            $coupons = $couponServices->selectWhere([['coupon_id', 'in', $coupon_ids]],'coupon_id,title');
            if($coupons){
                $coupons = $coupons->toArray();
                $coupons = array_column($coupons,null,'coupon_id');
            }
            foreach ($lottery['prize'] as &$prize) {
                $prize['coupon_title'] = $prize['goods_image'] = '';
                if ($prize['type'] == 6) {
                    $prize['goods_image'] = $products[$prize['product_id']]['image'] ?? '';
                }
                if ($prize['type'] == 5) {
                    $prize['coupon_title'] = $coupons[$prize['coupon_id']]['title'] ?? '';
                }
            }
        }
        return $lottery;
    }

    public function getFactorLotteryCache(int $factor)
    {

        $lottery = $this->dao->getFactorLottery($factor);
        return $lottery ? $lottery->toArray() : null;

    }

    /**
     * 验证用户抽奖资格（用户等级、付费会员、用户标签）
     * @param int $uid
     * @param int $lottery_id
     * @param array $userInfo
     * @param array $lottery
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function checkoutUserAuth(int $uid, int $lottery_id,  $userInfo, array $lottery = [])
    {
        if (!$userInfo) {
            /** @var UserRepository $UserRepository */
            $userInfo = app()->make(UserRepository::class)->get($uid);
        }
        if (!$userInfo) {
            throw new ValidateException('用户不存在');
        }
        if (!$lottery) {
            $lottery = $this->dao->getLottery($lottery_id, '*', [], true);
        }
        if (!$lottery) {
            throw new ValidateException('该活动已经下架，请持续关注');
        }
        //部分用户参与
        if ($lottery['attends_user'] == 2) {
            //用户等级
            if ($lottery['user_level'] && !in_array($userInfo->level, $lottery['user_level'])) {
                throw new ValidateException('您暂时无法参与该活动');
            }
//            //用户标签
//            if ($lottery['user_label']) {
//                /** @var UserLabelRelationServices $userlableRelation */
//                $userlableRelation = app()->make(UserLabelRelationServices::class);
//                $user_labels = $userlableRelation->getUserLabels($uid);
//                if (!array_intersect($lottery['user_label'], $user_labels)) {
//                    throw new ValidateException('您暂时无法参与该活动');
//                }
//            }
//            //是否是付费会员
//            if ($lottery['is_svip'] != -1) {
//                if (($lottery['is_svip'] == 1 && $userInfo['is_money_level'] <= 0) || ($lottery['is_svip'] == 0 && $userInfo['is_money_level'] > 0)) {
//                    throw new ValidateException('您暂时无法参与该活动');
//                }
//            }
        }
        return true;
    }


    /**
     * 抽奖
     * @param int $uid
     * @param int $lottery_id
     * @return mixed
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function luckLottery(int $uid, int $lottery_id)
    {

        $userServices = app()->make(UserRepository::class);
        $userInfo = $userServices->get($uid);
        if (!$userInfo) {
            throw new ValidateException('用户不存在');
        }

        $lottery = $this->dao->getLottery($lottery_id, '*', [], true);
        if (!$lottery) {
            throw new ValidateException('该活动已经下架，请持续关注');
        }
        $userInfo = $userInfo->toArray();
        $lottery = $lottery->toArray();
        //验证用户身份
        $this->checkoutUserAuth($uid, $lottery_id, $userInfo, $lottery);

        $lotteryPrizeServices = app()->make(LuckLotteryPrizeRepository::class);
        $lotteryPrize = $lotteryPrizeServices->getPrizeList($lottery_id);
        if (!$lotteryPrize) {
            throw new ValidateException('该活动状态有误，请联系管理员');
        }

        if ($this->getLotteryNum($uid, $lottery_id, $userInfo, $lottery) < 1) {
            //抽奖类型：1:积分2：余额3：下单支付成功4：订单评价5：拉新人
            switch ($lottery['factor']) {
                case 1:
                    throw new ValidateException('积分不足，没有更多抽奖次数');
                    break;
                case 2:
                    throw new ValidateException('余额不足，没有更多抽奖次数');
                    break;
                case 3:
                    throw new ValidateException('购买商品之后获得更多抽奖次数');
                    break;
                case 4:
                    throw new ValidateException('订单完成评价之后获得更多抽奖次数');
                    break;
                case 5:
                    throw new ValidateException('邀请更多好友获取抽奖次数');
                    break;
                default:
                    throw new ValidateException('暂未有该类型活动');
                    break;
            }
        }

        if ($lottery['factor'] == 1) {//积分抽奖
            $lotteryRecordServices = app()->make(LuckLotteryRecordRepository::class);
            $data = $lotteryRecordServices->getLotteryNum($uid, (int)$lottery['id']);

            $lotteryData['todayCount'] = (int)max(bcsub((string)$lottery['lottery_num'], (string)$data['todayCount'], 0), 0);
            $lotteryData['totalCount'] = (int)max(bcsub((string)$lottery['total_lottery_num'], (string)$data['totalCount'], 0), 0);
            if ($lotteryData['todayCount'] <= 0) {
                throw new ValidateException('本次活动当天抽奖次数已用完!');
            }
            if ($lotteryData['totalCount'] <= 0) {
                throw new ValidateException('本次活动总抽奖次数已用完!');
            }
        }

        $luckPrizeServices = app()->make(LuckLotteryPrizeRepository::class);
        //随机抽奖
        $prize = $luckPrizeServices->getLuckPrize($lotteryPrize);
        if (!$prize) {
            throw new ValidateException('该活动状态有误，请联系管理员');
        }
        return Db::transaction(function () use ($prize, $luckPrizeServices, $uid, $lotteryPrize, $userInfo, $lottery) {
            //中奖扣除积分、余额
            $this->lotteryFactor($uid, $userInfo, $lottery);
            //中奖减少奖品数量
            $luckPrizeServices->decPrizeNum($prize['id'], $prize);
            $luckLotteryRecordRepository = app()->make(LuckLotteryRecordRepository::class);
            //中奖写入记录
            $record = $luckLotteryRecordRepository->insertPrizeRecord($uid, $prize, $userInfo);
            //不是站内商品直接领奖
            if ($prize['type'] != 6) {
                $luckLotteryRecordRepository->receivePrize($uid, (int)$record->id);
            }
            $prize['lottery_record_id'] = $record->id;
            return $prize;
        });
    }


    /**
     * 抽奖消耗扣除用户积分、余额等
     * @param int $uid
     * @param array $userInfo
     * @param array $lottery
     * @return bool
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function lotteryFactor(int $uid, array $userInfo, array $lottery)
    {
        if (!$userInfo || !$lottery) {
            return true;
        }
        //抽奖类型：1:积分2：余额3：下单支付成功4：订单评价5：拉新人
        switch ($lottery['factor']) {
            case 1:
                if ($userInfo['integral'] > $lottery['factor_num']) {
                    $integral = bcsub((string)$userInfo['integral'], (string)$lottery['factor_num'], 0);
                } else {
                    $integral = 0;
                }
                $userServices = app()->make(UserRepository::class);
                $userBillServices = app()->make(UserIntegralBillRepository::class);
                $userBillServices->decBill( $uid, 'integral','lottery_use',[
                    'link_id' => $lottery['id'],
                    'status' => 1,
                    'title' => '参与抽奖使用积分',
                    'number' => $lottery['factor_num'],
                    'mark' => '参与抽奖使用' . $lottery['factor_num'] . '积分',
                    'balance' => $integral
                ]);
                if (!$userServices->update($uid, ['integral' => $integral])) {
                    throw new ValidateException('抽奖扣除用户积分失败');
                }
                break;
            case 2:
                if ($userInfo['now_money'] >= $lottery['factor_num']) {
                    $now_money = bcsub((string)$userInfo['now_money'], (string)$lottery['factor_num'], 2);
                } else {
                    throw new ValidateException('抽奖失败，余额不足！');
                }
                $userServices = app()->make(UserRepository::class);
                /** @var UserMoneyServices $userMoneyServices */
                $userMoneyServices = app()->make(UserMoneyServices::class);
                $userMoneyServices->income('lottery_use_money', $uid, $lottery['factor_num'], $now_money, $lottery['id']);
                if (!$userServices->update($uid, ['now_money' => $now_money], 'uid')) {
                    throw new ValidateException('抽奖扣除用户余额失败');
                }
                break;
            case 3:
            case 4:
                //销毁抽奖次数缓存
                $this->delCacheLotteryNum($uid, $lottery['factor'] == 3 ? 'order' : 'comment');
                break;
            case 5:
                $userServices = app()->make(UserRepository::class);
                $spread_lottery = 0;
                if ($userInfo['spread_lottery'] > 1) {
                    $spread_lottery = $userInfo['spread_lottery'] - 1;
                }
                if (!$userServices->update($uid, ['spread_lottery' => $spread_lottery], 'uid')) {
                    throw new ValidateException('抽奖扣除用户推广获取抽奖次数失败');
                }
                break;
            default:
                throw new ValidateException('暂未有该类型活动');
                break;
        }
        return true;
    }




    /**
     * 获取用户某个抽奖活动剩余抽奖次数
     * @param int $uid
     * @param int $lottery_id
     * @param array $userInfo
     * @param array $lottery
     * @return false|float|int|mixed
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getLotteryNum(int $uid, int $lottery_id, array $userInfo = [], array $lottery = [])
    {
        if (!$userInfo) {
            /** @var UserRepository $UserRepository */
            $userInfo = app()->make(UserRepository::class)->get($uid);
        }
        if (!$userInfo) {
            throw new ValidateException('用户不存在');
        }
        if (!$lottery) {
            $lottery = $this->dao->getLottery($lottery_id, '*', [], true);
        }
        if (!$lottery) {
            throw new ValidateException('该活动已经下架，请持续关注');
        }
        //抽奖类型：1:积分2：余额3：下单支付成功4：订单评价5：拉新人
        switch ($lottery['factor']) {
            case 1:
                return $userInfo['integral'] > 0 && $lottery['factor_num'] > 0 ? floor($userInfo['integral'] / $lottery['factor_num']) : 0;
                break;
//            case 2:
//                return $userInfo['now_money'] > 0 && $lottery['factor_num'] > 0 ? floor($userInfo['now_money'] / $lottery['factor_num']) : 0;
//                break;
//            case 3:
//                return $this->getCacheLotteryNum($uid, 'order');
//                break;
//            case 4:
//                return $this->getCacheLotteryNum($uid, 'comment');
//                break;
//            case 5:
//                return $userInfo['spread_lottery'] ?? 0;
//                break;
            default:
                throw new ValidateException('暂未有该类型活动');
                break;
        }
    }

    /**
     * 修改抽奖活动以及奖品
     * @param int $id
     * @param array $data
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function edit(int $id, array $data)
    {
        $lottery = $this->dao->getLottery($id);

        if (!$lottery) {
            throw new ValidateException('抽奖活动不存在');
        }
        $newPrizes = $data['prize'];
        unset($data['prize'], $data['id']);
        $prize_num = $this->lottery_type[1];
        if (count($newPrizes) != $prize_num) {
            throw new ValidateException('请选择' . $prize_num . '个奖品');
        }
        $luckLotteryPrizeRepository = app()->make(LuckLotteryPrizeRepository::class);
        $prizes = $luckLotteryPrizeRepository->getLotteryPrizeList($id);



        Db::transaction(function () use ($id, $lottery, $data, $newPrizes, $prizes, $luckLotteryPrizeRepository) {
            $updateIds = array_column($newPrizes, 'id');
            $oldIds = array_column($prizes, 'id');
            $delIds = array_merge(array_diff($oldIds, $updateIds));
            $insert = [];
            $time = time();
            $sort = 1;
            foreach ($newPrizes as $prize) {
                $prize = $luckLotteryPrizeRepository->checkPrizeData($prize);
                $prize['sort'] = $sort;
                if (isset($prize['id']) && $prize['id']) {
                    $prizeId = $prize['id'];
                    if (!$prize['lottery_id']) {
                        throw new ValidateException('缺少活动ID');
                    }
                    $luckLotteryPrizeRepository->update($prize['id'], $prize);
//                    if (!$luckLotteryPrizeRepository->update($prize['id'], $prize)) {
//                        throw new ValidateException('修改奖品失败');
//                    }
                } else {
                    unset($prize['id']);
                    $prize['lottery_id'] = $id;
                    $prize['add_time'] = $time;
                    $prize['sort'] = $sort;
                    $prizeId = $luckLotteryPrizeRepository->insert($prize);
                    if (!$prizeId) {
                        throw new ValidateException('新增奖品失败');
                    }
                }
                $sort++;

                //抽奖商品库存加入redis
                CacheServices::setStock((string)$prizeId, (int)$prize['total'], 6);
            }
            if ($delIds) {
                if (!(new LuckPrize())->whereIn('id',$delIds)->update(['is_del' => 1])) {
                    throw new ValidateException('删除奖品失败');
                }
            }
            $this->dao->update($id, $data);
            //上架

            if (!$lottery['status'] && $data['status']) {
                $this->setStatus($id, $data['status']);
            }
            return true;
        });
        return true;
    }


    public function setStatus(int $id, $status)
    {
        if (!$id) return false;
        $lottery = $this->dao->getLottery($id, 'id,factor');
        if (!$lottery) {
            return false;
        }
        //每一种抽奖类型只有一个上架
        if ($status) {
             $this->dao->search(['factor' => $lottery['factor']])->update(['status' => 0]);
        }
        return $this->dao->update($id, ['status' => $status]);
    }

    /**
     * 根据主键查询
     * @param int $id
     * @param null $except
     * @return bool
     * @author Qinii
     */
    public function exists(int $id, $except = null)
    {
        return $this->dao->fieldExists($this->dao->getPk(), $id, $except);
    }




}
